package edu.sjtu.grid.workflow.facts;

import edu.sjtu.grid.workflow.Util;
import edu.sjtu.grid.workflow.facts.PC;
import edu.sjtu.grid.workflow.facts.Job;

public class Mapping {
	private Facts facts = null;
	private Job job = null;
	private PC pc = null;
	private double fromTime = 0;
	private double toTime = 0;
	
	public Mapping(Facts facts, Job job, PC pc, double fromTime, double toTime)
	{
		this.facts = facts;
		this.job = job;
		this.pc = pc;
		this.fromTime = fromTime;
		this.toTime = toTime;	
	}
	
	public boolean equals2(Mapping map)
	{
		if(job == map.getJob() && pc == map.getPC())
			return true;
		else
			return false;
	}
	
	public boolean equals(Mapping map)
	{
		if(job == map.getJob() 
				&& pc == map.getPC() 
				&& Util.isEqual(fromTime, map.getFromTime())
				&& Util.isEqual(toTime, map.getToTime()))
			return true;
		else
			return false;
	}
	public String toXML(String prefix, String tab)
	{
		StringBuilder s = new StringBuilder();
		s.append(prefix + "<mapping")
			.append(" jobref=").append("\"" + job.getId() + "\"")
			.append(" pcref=").append("\"" + pc.getId() + "\"")
			.append(" fromtime=").append("\"" + Util.formatOutputDouble(fromTime) + "\"")
			.append(" totime=").append("\"" + Util.formatOutputDouble(toTime) + "\"")
			.append(" />\n");
		return s.toString();
	}
	
	public String toString()
	{
		StringBuilder s = new StringBuilder();
		s.append(job.getId() + "=>" + pc.getId() + "@" + fromTime + ","+ toTime);
		return s.toString();
	}
	
	public double getRealComputationCost()
	{
		return pc.getCost().getRealCost(fromTime, toTime);
	}
	
	public double getRealComputationCost_AvgCost()
	{
		return pc.getCost().getAvgCost() * (toTime - fromTime);
		//return pc.getCost().getRealCost(fromTime, toTime);
	}
	
	public double getRealComputationCost_InitialCost()
	{
		return pc.getCost().getInitialCost() * (toTime - fromTime);
		//return pc.getCost().getRealCost(fromTime, toTime);
	}
	
	public double getRealTransCost(Run run)
	{
		double sum = 0;
		double dataTransCost = this.facts.getPcs().getDataTransCost();
		for(Job parent : this.job.getParentJobList())
		{
			if(run.getMapping(parent)!= null 
					&& this.pc != run.getMapping(parent).getPC())
			{
				long data = this.job.getParentToDataSize().get(parent);
				double cost = dataTransCost * data;
				sum += cost;
			}
		}
		return sum;
	}
	
	public double getRealTransAndComputationCost(Run run)
	{
		return this.getRealTransCost(run) + this.getRealComputationCost();
	}
	
	public double getRealTransAndComputationCost_AvgCost(Run run)
	{
		return this.getRealTransCost(run) + this.getRealComputationCost_AvgCost();
	}
	
	public double getRealTransAndComputationCost_InitialCost(Run run)
	{
		return this.getRealTransCost(run) + this.getRealComputationCost_InitialCost();
	}
	
	public double getRealTransAndComputationCost(Mapping parentMapping)
	{
		assert(this.job.getParentToDataSize().containsKey(parentMapping.getJob()));
		
		if(this.getPC() == parentMapping.getPC())
			return this.getRealComputationCost();
		
		double dataTransCost = this.facts.getPcs().getDataTransCost();
		long data = this.job.getParentToDataSize().get(parentMapping.getJob());
		double transCost = dataTransCost * data;
		return transCost + this.getRealComputationCost();
	}
	
	public Job getJob()
	{
		return this.job;
	}
	
	public PC getPC()
	{
		return this.pc;
	}

	public double getFromTime()
	{
		return this.fromTime;
	}
	
	public double getToTime()
	{
		return this.toTime;
	}
}
